import pymysql.cursors
import datetime
import json
from decimal import *

WORK_MIN_HOURS = 8
WORK_SOME_OVER_HOURS = 10
WORK_PREFER_HOURS = 12
WORK_MAX_HOURS = 14

WORK_HOURS = [WORK_MIN_HOURS, WORK_SOME_OVER_HOURS, WORK_PREFER_HOURS, WORK_MAX_HOURS]

xls_columns = ["关联模块", "需求", "子需求", "任务", "X1", "负责人", "PV", "计划开始日期", "计划完成日期", "AC", "实际开始日期", "实际完成日期", "X2", "EV", "A", "备注","加班标志","节日标志"]


class WorkDay(object):
    def __init__(self, date: datetime.datetime, go_to_work: bool, holiday: bool):
        self.date = date
        self.go_to_work = go_to_work
        self.holiday = holiday


def make_work_day_dict() -> dict:

    work_day_dict = {}
    year = 2024
    begin = datetime.datetime(year, 1, 1)
    end = datetime.datetime(year+1, 1, 1)
    holiday_file_name = f'holiday-{year}.json'
    holiday_dict = {}
    with open(holiday_file_name, 'r', encoding='UTF-8') as holiday_file:
        holiday_dict = json.load(holiday_file)

    day = begin
    while day < end:
        weekday = day.isoweekday()
        go_to_work = True if weekday <= 5 else False
        holiday = False

        key = day.strftime('%m-%d')

        if key in holiday_dict:
            holiday_item = holiday_dict[key]
            if holiday_item['holiday']:
                go_to_work = False
                if holiday_item['wage'] > 2:
                    holiday = True
            else:
                go_to_work = True
                holiday = False

        work_day = WorkDay(day, go_to_work, holiday)

        work_day_dict[key] = work_day

        day = day + datetime.timedelta(days=1)

    return work_day_dict


WORK_DAY = make_work_day_dict()

def connection():
    c = pymysql.connect(host='localhost', user='payment', password='Bsoft@123', database='zarra_demo', cursorclass=pymysql.cursors.DictCursor)
    return c


def obj2sql(o) -> str:
    if o is None:
        return 'null'
    elif isinstance(o, datetime.datetime):
        return "'"+o.strftime("%Y-%m-%d 00:00:00")+"'"
    elif isinstance(o, int):
        return str(o)
    elif isinstance(o, Decimal):
        return str(o)
    else:
        return "'"+str(o)+"'"


def sum_pv_for_person_and_date(date: datetime.datetime, person: str) -> Decimal:
    sql = f"select ifnull(sum(pv),0) as pv from jijiao_detail where 计划开始日期 = %s and 负责人 = %s"
    c = connection()
    cursor = c.cursor()
    cursor.execute(sql, (date.strftime('%Y-%m-%d'), person))
    r = cursor.fetchone()
    return r['pv']


def insert_detail_row(values):
    if isinstance(values, dict):
        d = values['计划开始日期']
        d_key = d.strftime('%m-%d')
        work_day = WORK_DAY[d_key]
        values['加班标志'] = 0 if work_day.go_to_work else 1
        values['节日标志'] = 1 if work_day.holiday else 0
        array = [values[key] for key in xls_columns]
        array = map(obj2sql, array)
        insert_detail_row( ",".join(array))
    elif isinstance(values, str):
        columns = list(xls_columns)
        sql = f"insert into jijiao_detail ({','.join(columns)}) values ({values})"
        #print(sql)
        c = connection()
        cursor = c.cursor()
        cursor.execute(sql)
        c.commit()


def new_day_job(row: dict, date, pv: Decimal = Decimal(0)):
    new_job = dict(row)
    new_job['计划开始日期'] = date
    new_job['计划完成日期'] = date
    new_job['实际开始日期'] = date
    new_job['实际完成日期'] = date
    new_job['PV'] = pv
    new_job['AC'] = pv
    new_job['EV'] = pv
    new_job['A'] = pv * new_job["X1"] * new_job['X2']
    return new_job

def set_day_job_pv(row: dict, pv: Decimal):
    row['PV'] = pv
    row['AC'] = pv
    row['EV'] = pv
    row['A'] = pv * row["X1"] * row['X2']


def adjust_day_job(row: dict, work_hours: Decimal, total_pv, min_final_total_pv) -> Decimal:
    used_hours = Decimal(0)
    if 'used_hours' in row:
        used_hours = row['used_hours']
    else:
        day = row['计划开始日期']
        person = row['负责人']
        used_hours = sum_pv_for_person_and_date(day, person)
        row['used_hours'] = used_hours
    last_pv = row['PV']
    this_pv = Decimal(work_hours) - used_hours - last_pv
    max_this_pv = max(total_pv, min_final_total_pv)

    this_pv = this_pv if this_pv <= max_this_pv else max_this_pv

    set_day_job_pv(row, last_pv+this_pv)

    return this_pv


def split_job(row: dict):
    person = row['负责人']
    work_begin = row['计划开始日期']
    work_end = row['计划完成日期']
    work_end = work_end if work_end is not None else work_begin
    day = work_begin
    total_pv = row['PV']

    used_hours = sum_pv_for_person_and_date(day, person)
    work_day_jobs = []
    overwork_day_jobs = []

    while day <= work_end:
        key = day.strftime('%m-%d')
        work_day = WORK_DAY[key]
        if work_day.go_to_work:
            work_day_jobs.append(new_day_job(row, day))
        else:
            item = new_day_job(row, day)
            item['加班标志'] = 1
            item['节日标志'] = 1 if work_day.holiday else 0
            overwork_day_jobs.append(item)

        day = day + datetime.timedelta(days=1)

    work_day_count = len(work_day_jobs)
    need_over_work = True if work_day_count * WORK_MAX_HOURS <= (total_pv + used_hours) else False
    min_total_pv = 0 if need_over_work else Decimal(0)

    for hours in WORK_HOURS:
        if total_pv > min_total_pv:
            for work_day_job in work_day_jobs:
                if total_pv > min_total_pv:
                    this_pv = adjust_day_job(work_day_job, hours, total_pv, 0)
                    total_pv -= this_pv

    if total_pv > 0:
        for hours in WORK_HOURS:
            if total_pv > 0:
                for work_day_job in overwork_day_jobs:
                    if total_pv > 0:
                        this_pv = adjust_day_job(work_day_job, hours,  total_pv, 0)
                        total_pv -= this_pv

    if total_pv > 0:
        print('***********************Error****************************')
        print(row)
        print('***************************************************')

    return work_day_jobs, overwork_day_jobs


def main():
    c = connection()
    with c.cursor() as cursor:
        cursor.execute("delete from jijiao_detail where 1=1;")
        c.commit()

        sql = '''select 关联模块,需求,子需求,任务,负责人,计划开始日期,ifnull(计划完成日期,计划开始日期) as 计划完成日期,实际开始日期,实际完成日期,备注,PV,AC,EV,X1,X2,A from jijiao
                 where 负责人 is not null 
                 -- and 计划开始日期 >= '2024-06-11' and 计划开始日期 <= '2024-06-19' and 负责人 = '夏申频'
                 order by 负责人,实际开始日期,关联模块,需求,子需求,任务'''
        cursor.execute(sql)
        row = cursor.fetchone()

        need_process_items = []

        while row is not None:
            row['加班标志'] = 0
            row['节日标志'] = 0
            if row['计划开始日期'] == row['计划完成日期']:
                insert_detail_row(row)
            else:
                need_process_items.append(row)

            row = cursor.fetchone()

        for row in need_process_items:
            work, over_work = split_job(row)
            for row in work:
                if row['PV'] > 0:
                    insert_detail_row(row)
            for row in over_work:
                if row['PV'] > 0:
                    insert_detail_row(row)




def test():
    row = {'关联模块': '支付通道管理','需求': '支付核心', '子需求': 'h5支付', '任务': '后端-h5支付', '负责人': '夏申频',
           '计划开始日期': datetime.datetime(2024, 7, 6, 0, 0),
           '计划完成日期': datetime.datetime(2024, 7, 8, 0, 0),
           '实际开始日期': datetime.datetime(2024, 7, 4, 0, 0),
           '实际完成日期': datetime.datetime(2024, 7, 6, 0, 0), '备注': None, 'PV': Decimal('32.00'), 'AC': Decimal('32.00'), 'EV': Decimal('32.00'), 'X1': Decimal('1.30'), 'X2': Decimal('1.50'), 'A': Decimal('62.40')
           }


    w,h = split_job(row)

    print(w)
    print(h)


if __name__ == '__main__':
    main()